#include <gtest/gtest.h>
#include <vector>
#include <fstream>
#include <cstring>
#include "pcm_aac_encoder.h"
#include "utils_log.h"
#include "utils_init.h"
#include "common_init.h"
#include "nlohmann/json.hpp"

using namespace El::Muxer;

class PcmAacEncoderTest : public ::testing::Test {
protected:
    static void SetUpTestSuite() {
        // 初始化基础库 - 只执行一次
        nlohmann::json config;
        config["log_level"] = "debug";
        config["log_to_file"] = false;
        El::Utils::base_init(config);

        // 初始化配置
        config.clear();
        config["general"] = "/mnt/config/config";
        config["default"] = "/mnt/config/default";
        config["product"] = "/usr/etc/custom/product.yaml";
        El::Common::common_init(config);
    }

    void SetUp() override
    {
        // 每个测试用例执行前清空缓冲区
    }

    void TearDown() override
    {
        // 每个测试用例执行后清理
    }

    // 从文件读取 PCM 数据
    std::vector<uint8_t> ReadPcmFile(const std::string& file_path)
    {
        std::ifstream file(file_path, std::ios::binary);
        if (!file.is_open()) {
            EL_ERROR("无法打开PCM文件: {}", file_path);
            return std::vector<uint8_t>();
        }

        file.seekg(0, std::ios::end);
        size_t file_size = file.tellg();
        file.seekg(0, std::ios::beg);

        std::vector<uint8_t> data(file_size);
        file.read(reinterpret_cast<char*>(data.data()), file_size);
        file.close();

        EL_INFO("成功读取PCM文件: {}, 大小: {} 字节", file_path, file_size);
        return data;
    }

    // 将数据写入文件
    bool WriteToFile(const std::string& file_path, const std::vector<uint8_t>& data)
    {
        std::ofstream file(file_path, std::ios::binary);
        if (!file.is_open()) {
            EL_ERROR("无法写入文件: {}", file_path);
            return false;
        }

        file.write(reinterpret_cast<const char*>(data.data()), data.size());
        file.close();

        EL_INFO("成功写入文件: {}, 大小: {} 字节", file_path, data.size());
        return true;
    }

    // 计算PCM时长（秒）
    double CalculatePcmDuration(size_t data_size, int sample_rate, int channels, int bytes_per_sample)
    {
        size_t total_samples = data_size / (channels * bytes_per_sample);
        return static_cast<double>(total_samples) / sample_rate;
    }
};

// 主测试用例：转换 mic.pcm 为 AAC
// mic.pcm 参数：16位小端，44100Hz采样率
TEST_F(PcmAacEncoderTest, ConvertMicPcmToAac)
{
    // PCM 文件路径（相对于测试目录）
    const std::string pcm_file_path = "./mic.pcm";

    // 读取PCM文件
    std::vector<uint8_t> pcm_data = ReadPcmFile(pcm_file_path);

    if (pcm_data.empty()) {
        GTEST_SKIP() << "PCM 测试文件不存在或为空: " << pcm_file_path;
    }

    // PCM 文件参数
    const int sample_rate = 44100;    // 44.1kHz
    const int channels = 1;           // 单声道（根据你的描述，如果是立体声请改为2）
    const int bitrate = 128000;       // 128kbps AAC 比特率
    const PcmAacEncoder::PcmFormat format = PcmAacEncoder::PcmFormat::S16LE;

    // 计算音频时长
    double duration = CalculatePcmDuration(pcm_data.size(), sample_rate, channels, 2);
    EL_INFO("PCM 音频时长: {:.2f} 秒", duration);

    // 初始化编码器
    PcmAacEncoder encoder;
    ASSERT_TRUE(encoder.Initialize(sample_rate, channels, format, bitrate))
        << "编码器初始化失败";

    EL_INFO("开始转码 PCM -> AAC...");

    // 分块处理PCM数据（模拟流式处理）
    const size_t chunk_size = 8192;  // 8KB 块大小
    size_t total_processed = 0;
    size_t chunk_count = 0;
    std::vector<uint8_t> all_aac_data;

    while (total_processed < pcm_data.size()) {
        size_t current_chunk_size = std::min(chunk_size, pcm_data.size() - total_processed);

        // 处理数据块
        ASSERT_TRUE(encoder.ProcessInput(pcm_data.data() + total_processed, current_chunk_size))
            << "处理第 " << chunk_count << " 个数据块失败";

        // 获取转换后的 AAC 数据
        std::vector<uint8_t> chunk_aac_data;
        ASSERT_TRUE(encoder.GetData(chunk_aac_data));

        // 累积 AAC 数据
        if (!chunk_aac_data.empty()) {
            all_aac_data.insert(all_aac_data.end(),
                               chunk_aac_data.begin(),
                               chunk_aac_data.end());
            EL_DEBUG("数据块 {} 产生 {} 字节 AAC 数据", chunk_count, chunk_aac_data.size());
        }

        total_processed += current_chunk_size;
        chunk_count++;
    }

    EL_INFO("PCM 数据处理完成，共 {} 个数据块，{} 字节", chunk_count, total_processed);

    // 刷新编码器缓冲区获取剩余数据
    EL_INFO("刷新编码器缓冲区...");
    std::vector<uint8_t> final_data;
    ASSERT_TRUE(encoder.GetData(final_data, true));

    if (!final_data.empty()) {
        all_aac_data.insert(all_aac_data.end(),
                           final_data.begin(),
                           final_data.end());
        EL_INFO("刷新缓冲区获得 {} 字节 AAC 数据", final_data.size());
    }

    // 保存 AAC 文件
    const std::string output_file_path = "./mic.aac";
    ASSERT_TRUE(WriteToFile(output_file_path, all_aac_data))
        << "无法写入 AAC 文件";

    // 验证结果
    EXPECT_GT(chunk_count, 0u) << "应该处理至少一个数据块";
    EXPECT_EQ(total_processed, pcm_data.size()) << "应该处理完所有 PCM 数据";
    EXPECT_GT(all_aac_data.size(), 0u) << "应该产生 AAC 输出数据";

    // 验证 ADTS 头（AAC格式标识）
    ASSERT_GE(all_aac_data.size(), 7u) << "AAC 数据太短，至少应该包含一个 ADTS 头";
    EXPECT_EQ(all_aac_data[0], 0xFF) << "ADTS 同步字第一个字节应该是 0xFF";
    EXPECT_EQ((all_aac_data[1] & 0xF0), 0xF0) << "ADTS 同步字第二个字节高4位应该是 0xF";

    // 计算压缩率
    double compression_ratio = static_cast<double>(pcm_data.size()) / all_aac_data.size();
    EXPECT_GT(compression_ratio, 1.0) << "AAC 压缩率应该大于 1";

    EL_INFO("============================================");
    EL_INFO("转码完成统计:");
    EL_INFO("  输入文件: {}", pcm_file_path);
    EL_INFO("  输出文件: {}", output_file_path);
    EL_INFO("  PCM大小: {} 字节 ({:.2f} MB)", pcm_data.size(), pcm_data.size() / (1024.0 * 1024.0));
    EL_INFO("  AAC大小: {} 字节 ({:.2f} MB)", all_aac_data.size(), all_aac_data.size() / (1024.0 * 1024.0));
    EL_INFO("  压缩率: {:.2f}x", compression_ratio);
    EL_INFO("  音频时长: {:.2f} 秒", duration);
    EL_INFO("  采样率: {} Hz", sample_rate);
    EL_INFO("  声道数: {}", channels);
    EL_INFO("  比特率: {} kbps", bitrate / 1000);
    EL_INFO("============================================");
}

// 测试用例：转换双声道 44.1kHz PCM
TEST_F(PcmAacEncoderTest, ConvertMicPcmToAacStereo)
{
    const std::string pcm_file_path = "./mic.pcm";
    std::vector<uint8_t> pcm_data = ReadPcmFile(pcm_file_path);

    if (pcm_data.empty()) {
        GTEST_SKIP() << "PCM 测试文件不存在: " << pcm_file_path;
    }

    // 如果原始文件实际是双声道，使用这个测试
    const int sample_rate = 44100;
    const int channels = 2;           // 双声道
    const int bitrate = 192000;       // 192kbps（双声道通常需要更高比特率）
    const PcmAacEncoder::PcmFormat format = PcmAacEncoder::PcmFormat::S16LE;

    double duration = CalculatePcmDuration(pcm_data.size(), sample_rate, channels, 2);
    EL_INFO("PCM 音频时长（立体声）: {:.2f} 秒", duration);

    PcmAacEncoder encoder;
    ASSERT_TRUE(encoder.Initialize(sample_rate, channels, format, bitrate));

    // 一次性处理全部数据（简化版本）
    ASSERT_TRUE(encoder.ProcessInput(pcm_data.data(), pcm_data.size()));

    std::vector<uint8_t> aac_data;
    ASSERT_TRUE(encoder.GetData(aac_data, true));

    const std::string output_file_path = "./mic_stereo.aac";
    ASSERT_TRUE(WriteToFile(output_file_path, aac_data));

    EXPECT_GT(aac_data.size(), 0u);

    double compression_ratio = static_cast<double>(pcm_data.size()) / aac_data.size();
    EL_INFO("立体声转码完成: {} 字节 PCM -> {} 字节 AAC, 压缩率: {:.2f}x",
             pcm_data.size(), aac_data.size(), compression_ratio);
}

// 测试用例：带重采样的转码（44.1kHz -> 48kHz）
TEST_F(PcmAacEncoderTest, ConvertMicPcmWithResampling)
{
    const std::string pcm_file_path = "./mic.pcm";
    std::vector<uint8_t> pcm_data = ReadPcmFile(pcm_file_path);

    if (pcm_data.empty()) {
        GTEST_SKIP() << "PCM 测试文件不存在: " << pcm_file_path;
    }

    // 输入参数：44.1kHz
    const int input_sample_rate = 44100;
    const int input_channels = 1;

    // 输出参数：48kHz（标准采样率）
    const int output_sample_rate = 48000;
    const int output_channels = 1;
    const int bitrate = 128000;
    const PcmAacEncoder::PcmFormat format = PcmAacEncoder::PcmFormat::S16LE;

    double input_duration = CalculatePcmDuration(pcm_data.size(), input_sample_rate, input_channels, 2);
    EL_INFO("原始 PCM 音频时长: {:.2f} 秒 ({}Hz)", input_duration, input_sample_rate);

    PcmAacEncoder encoder;
    // 启用重采样：输入44.1kHz -> 输出48kHz
    ASSERT_TRUE(encoder.Initialize(output_sample_rate, output_channels, format, bitrate,
                                    input_sample_rate, input_channels));

    EL_INFO("开始带重采样的转码 ({}Hz -> {}Hz)...", input_sample_rate, output_sample_rate);

    ASSERT_TRUE(encoder.ProcessInput(pcm_data.data(), pcm_data.size()));

    std::vector<uint8_t> aac_data;
    ASSERT_TRUE(encoder.GetData(aac_data, true));

    const std::string output_file_path = "./mic_48k.aac";
    ASSERT_TRUE(WriteToFile(output_file_path, aac_data));

    EXPECT_GT(aac_data.size(), 0u);

    EL_INFO("重采样转码完成: {}Hz -> {}Hz, {} 字节 PCM -> {} 字节 AAC",
             input_sample_rate, output_sample_rate, pcm_data.size(), aac_data.size());
}

// 测试用例：小数据块流式处理
TEST_F(PcmAacEncoderTest, ConvertMicPcmSmallChunks)
{
    const std::string pcm_file_path = "./mic.pcm";
    std::vector<uint8_t> pcm_data = ReadPcmFile(pcm_file_path);

    if (pcm_data.empty()) {
        GTEST_SKIP() << "PCM 测试文件不存在: " << pcm_file_path;
    }

    const int sample_rate = 44100;
    const int channels = 1;
    const int bitrate = 128000;

    PcmAacEncoder encoder;
    ASSERT_TRUE(encoder.Initialize(sample_rate, channels, PcmAacEncoder::PcmFormat::S16LE, bitrate));

    // 使用非常小的数据块（模拟实时音频流）
    const size_t chunk_size = 1024;  // 1KB
    size_t total_processed = 0;
    std::vector<uint8_t> all_aac_data;

    EL_INFO("使用小数据块（{} 字节）流式处理...", chunk_size);

    while (total_processed < pcm_data.size()) {
        size_t current_chunk_size = std::min(chunk_size, pcm_data.size() - total_processed);

        ASSERT_TRUE(encoder.ProcessInput(pcm_data.data() + total_processed, current_chunk_size));

        std::vector<uint8_t> chunk_aac_data;
        ASSERT_TRUE(encoder.GetData(chunk_aac_data));

        if (!chunk_aac_data.empty()) {
            all_aac_data.insert(all_aac_data.end(),
                               chunk_aac_data.begin(),
                               chunk_aac_data.end());
        }

        total_processed += current_chunk_size;
    }

    // 刷新
    std::vector<uint8_t> final_data;
    ASSERT_TRUE(encoder.GetData(final_data, true));
    if (!final_data.empty()) {
        all_aac_data.insert(all_aac_data.end(),
                           final_data.begin(),
                           final_data.end());
    }

    const std::string output_file_path = "./mic_stream.aac";
    ASSERT_TRUE(WriteToFile(output_file_path, all_aac_data));

    EXPECT_GT(all_aac_data.size(), 0u);

    size_t chunk_count = (pcm_data.size() + chunk_size - 1) / chunk_size;
    EL_INFO("小数据块流式处理完成: {} 个数据块, {} 字节 AAC",
             chunk_count, all_aac_data.size());
}
